package com.yunhe.abnormal.service.data.impl;

import com.yunhe.abnormal.client.AuthorityClient;
import com.yunhe.abnormal.domain.data.AbnormalEvent;
import com.yunhe.abnormal.domain.data.AbnormalEventRecord;
import com.yunhe.common.exception.ObjectNotFoundException;
import com.yunhe.common.model.PageParam;
import com.yunhe.common.model.authority.UserDTO;
import com.yunhe.abnormal.repository.data.AbnormalEventRecordMeasRepository;
import com.yunhe.abnormal.repository.data.AbnormalEventRecordRepository;
import com.yunhe.abnormal.service.data.AbnormalEventRecordService;
import com.yunhe.abnormal.service.data.AbnormalEventService;
import com.yunhe.common.util.DateTimeUtils;
import com.yunhe.common.util.QueryUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.util.*;

@Service
public class AbnormalEventRecordServiceImpl implements AbnormalEventRecordService {
    @Autowired
    private AbnormalEventRecordRepository abnormalEventRecordRepository;
    @Autowired
    private AbnormalEventRecordMeasRepository abnormalEventRecordMeasRepository;
    @Autowired
    private AbnormalEventService abnormalEventService;
    @Autowired
    private AuthorityClient authorityClient;


    private void processBeforeSave(AbnormalEventRecord abnormalEventRecord) throws ObjectNotFoundException {
        Long userId = abnormalEventRecord.getUserIdProcess();
        if (userId != null) {
            UserDTO user = authorityClient.getUserById(userId).getBody().getResults();
            if (user != null && user.getTitle() != null) {
                abnormalEventRecord.setUserTitleProcess(user.getTitle());
            } else {
                throw new ObjectNotFoundException("未找到ID为" + userId +"的用户");
            }
        } else {
            abnormalEventRecord.setUserTitleProcess("System");
        }
        String dtime = abnormalEventRecord.getDtime();
        if (dtime == null) {
            abnormalEventRecord.setDtime(DateTimeUtils.format(new Date()));
        }
    }

    @Override
    public AbnormalEventRecord create(AbnormalEventRecord abnormalEventRecord) throws ObjectNotFoundException {
        abnormalEventRecord.setId(null);
        processBeforeSave(abnormalEventRecord);
        AbnormalEventRecord result = abnormalEventRecordRepository.save(abnormalEventRecord);
        //还需要记录点号
        //找出已生成的记录的异常规则ID和告警等级ID
        //通过这两个ID查找出数据源点号
        return result;
    }

    @Override
    public Iterable<AbnormalEventRecord> create(List<AbnormalEventRecord> abnormalEventRecords) throws ObjectNotFoundException {
        List<AbnormalEventRecord> results = new ArrayList<>();
        for (AbnormalEventRecord abnormalEventRecord : abnormalEventRecords) {
            results.add(create(abnormalEventRecord));
        }
        return results;
    }

    @Override
    public void delete(Long id) {
        abnormalEventRecordMeasRepository.deleteByRecordId(id);
        abnormalEventRecordRepository.deleteById(id);
    }

    @Override
    public AbnormalEventRecord update(AbnormalEventRecord abnormalEventRecord) throws ObjectNotFoundException {
        processBeforeSave(abnormalEventRecord);
        AbnormalEventRecord result = abnormalEventRecordRepository.save(abnormalEventRecord);
        return result;
    }

    @Override
    public AbnormalEventRecord update(Long id,
                                      Optional<String> dtime,
                                      Optional<Long> userIdProcess,
                                      Optional<String> records) throws ObjectNotFoundException {
        AbnormalEventRecord byId = abnormalEventRecordRepository.findById(id).orElse(null);
        if (byId == null) {
            throw new ObjectNotFoundException("未找到ID为" + id + "的异常事件记录");
        }
        dtime.ifPresent(byId::setDtime);
        userIdProcess.ifPresent(byId::setUserIdProcess);
        records.ifPresent(byId::setRecords);
        processBeforeSave(byId);
        AbnormalEventRecord result = abnormalEventRecordRepository.save(byId);
        return result;
    }

    @Override
    public AbnormalEventRecord findById(Long id) {
        return abnormalEventRecordRepository.findById(id).orElse(null);
    }

    @Override
    public Iterable<AbnormalEventRecord> retrieve(Optional<Long> userId,
                                                  Optional<Long> eventId,
                                                  Optional<String> dtime,
                                                  Optional<String> queryStr,
                                                  PageParam pageParam) {
        Specification spec = (Specification<AbnormalEventRecord>) (root, query, cb) -> {
            List<Predicate> criteria = new ArrayList<>();
            if (userId.isPresent()) {
                criteria.add(cb.equal(root.get("userId"), userId.get()));
            }
            if (eventId.isPresent()) {
                AbnormalEvent byId = abnormalEventService.findById(eventId.get());
                if (byId != null) {
                    criteria.add(cb.equal(root.get("abnormalEvent").as(AbnormalEvent.class), byId));
                }
            }
            if (dtime.isPresent()) {
                String[] split = dtime.get().split(",");
                List<String> dtimeList = new ArrayList<>();
                Collections.addAll(dtimeList, split);
                Path<String> dtimePath = root.get("dtime");
                if (dtimeList.size() == 1) {
                    String date = dtimeList.get(0);
                    criteria.add(cb.equal(dtimePath, date));
                } else if (dtimeList.size() == 2) {
                    String start = dtimeList.get(0);
                    String end = dtimeList.get(1);
                    criteria.add(cb.between(dtimePath, start, end));
                }
            }
            if (criteria.size() == 1) {
                query.where(criteria.get(0));
            } else {
                query.where(criteria.toArray(new Predicate[0]));
            }
            return null;
        };
        Iterable<AbnormalEventRecord> results;
        if (QueryUtil.needPaging(pageParam)) {
            List<String> sortList = pageParam.getSort();
            if (sortList == null) {
                List<String> list = new ArrayList<>();
                list.add("-dtime");
                pageParam.setSort(list);
            }
            results = abnormalEventRecordRepository.findAll(spec, QueryUtil.getPageRequest(pageParam));
        } else {
            Sort sort = pageParam == null ? null : QueryUtil.getSort(pageParam.getSort());
            if (sort != null) {
                results = abnormalEventRecordRepository.findAll(spec, sort);
            } else {
                List<String> list = new ArrayList<>();
                list.add("-dtime");
                sort = QueryUtil.getSort(list);
                results = abnormalEventRecordRepository.findAll(spec, sort);
            }
        }
        return results;
    }

    @Override
    public AbnormalEventRecord findByAbnormalEventId(Long eventId) {
        return abnormalEventRecordRepository.findByAbnormalEventId(eventId);
    }
}
